{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Building a Controller for a storage unit"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The following documents the development of a new controller.\n",
    "In this case we are going to implement an arbitrary controllable storage unit.\n",
    "This could be a water tank, an underground cavern storage or some sort of reservoir storage.\n",
    "The purpose of this storage is to store mass (of a fluid). The temperature or changes in the\n",
    "composition are neglected."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Modelling a mass storage\n",
    "\n",
    "In order to simulate a storage system we use the mass storage element of pandapipes. The mass flow\n",
    "of a storage can be positive or negative.\n",
    "\n",
    "For storage elements the signing is based on the consumer viewpoint (positive flow means \"charging\"\n",
    "of the storage, negative flow means that the fluid is leaving the storage).\n",
    "\n",
    "As pandapipes is not a time dependent simulation tool and there is no time domain parameter in\n",
    "default pipe flow calculations, the amount of stored mass is not updated during any regular pipe\n",
    "flow calculation. In order to update the \"filling level\" (State of Charge) (`m_stored_kg`),\n",
    "we build our own storage controller and keep track of the SoC."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Controller init\n",
    "First we start by creating a new file *control/storage_control.py*, containing our new class."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We import and inherit from the parent class `Controller` (from pandapower) and override methods that are only dummy methods in the parent class.\n",
    "\n",
    "The most important methods are\n",
    "- `time_step`,\n",
    "which will be called by `run_time_series` -> `run_loop` -> `run_time_step` -> `control_time_step` -> `Controller.time_step(net, timestep)`\n",
    "- `write_to_net`,\n",
    "which will afterwards be called by `run_time_series` -> `run_loop` -> `run_time_step` -> `run_control_fct` -> `control_implementation` -> `_control_step` -> `Controller.control_step(net)`.\n",
    "\n",
    "Depending on the particular storage design, they may need to be adapted to specify the storage's\n",
    "charging behavior or to include more, user-defined variables, i.e. filling height."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [],
   "source": [
    "import pandapipes as pp\n",
    "from pandapower.control.basic_controller import Controller\n",
    "\n",
    "\n",
    "class StorageController(Controller):\n",
    "    \"\"\"\n",
    "        Example class of a Storage-Controller. Models an abstract mass storage.\n",
    "    \"\"\"\n",
    "    def __init__(self, net, sid, data_source=None, mdot_profile=None, in_service=True,\n",
    "                 recycle=False, order=0, level=0, duration_timestep_h=1, **kwargs):\n",
    "        super().__init__(net, in_service=in_service, recycle=recycle, order=order, level=level,\n",
    "                    initial_pipeflow = True, **kwargs)\n",
    "        \n",
    "        # read storage attributes from net\n",
    "        self.sid = sid  # index of the controlled storage\n",
    "        self.junction = net.mass_storage.at[sid, \"junction\"]\n",
    "        self.mdot_kg_per_s = net.mass_storage.at[sid, \"mdot_kg_per_s\"]\n",
    "        self.name = net.mass_storage.at[sid, \"name\"]\n",
    "        self.storage_type = net.mass_storage.at[sid, \"type\"]\n",
    "        self.in_service = net.mass_storage.at[sid, \"in_service\"]\n",
    "        self.scaling = net.mass_storage.at[sid, \"scaling\"]\n",
    "        self.applied = False\n",
    "\n",
    "        # specific attributes\n",
    "        self.max_m_kg = net.mass_storage.at[sid, \"max_m_stored_kg\"]\n",
    "        self.min_m_kg = net.mass_storage.at[sid, \"min_m_stored_kg\"]\n",
    "        self.m_stored_kg = net.mass_storage.at[sid, \"init_m_stored_kg\"]\n",
    "\n",
    "        # profile attributes\n",
    "        self.data_source = data_source\n",
    "        self.mdot_profile = mdot_profile\n",
    "        self.last_time_step = 0\n",
    "        self.duration_ts_sec = duration_timestep_h * 3600\n",
    "\n",
    "    # In a time-series simulation the mass storage should read new flow values from a profile and keep track\n",
    "    # of its amount of stored mass as depicted below.\n",
    "    def time_step(self, net, time):\n",
    "        # keep track of the stored mass (the duration of one time step is given as input to the controller)\n",
    "        if self.last_time_step is not None:\n",
    "            # The amount of mass that flowed into or out of the storage in the last timestep is added\n",
    "            # requested change of mass:\n",
    "            self.delta_m_kg_req = (self.mdot_kg_per_s * (time - self.last_time_step)\n",
    "                                   * self.duration_ts_sec)\n",
    "            # limit by available mass and free capacity in the storage:\n",
    "            if self.delta_m_kg_req > 0:  # \"charging\"\n",
    "                self.delta_m_kg_real = min(self.delta_m_kg_req, self.max_m_kg - self.m_stored_kg)\n",
    "            else:  # \"discharging\", delta < 0\n",
    "                self.delta_m_kg_real = max(self.delta_m_kg_req, self.min_m_kg - self.m_stored_kg)\n",
    "            self.m_stored_kg += self.delta_m_kg_real\n",
    "            self.mdot_kg_per_s = self.delta_m_kg_real / ((time - self.last_time_step)\n",
    "                                                         * self.duration_ts_sec)\n",
    "        self.last_time_step = time\n",
    "\n",
    "        # read new values from a profile\n",
    "        if self.data_source:\n",
    "            if self.mdot_profile is not None:\n",
    "                self.mdot_kg_per_s = self.data_source.get_time_step_value(time_step=time,\n",
    "                                                                          profile_name=self.mdot_profile)\n",
    "                self.m_stored_kg *= self.scaling * self.in_service\n",
    "\n",
    "        self.applied = False  # reset applied variable\n",
    "\n",
    "    # Some convenience methods to calculate indicators for the state of charge:\n",
    "    def get_stored_mass(self):\n",
    "        # return the absolute stored mass\n",
    "        return self.m_stored_kg\n",
    "\n",
    "    def get_free_stored_mass(self):\n",
    "        # return the stored mass excl. minimum filling level\n",
    "        return self.m_stored_kg - self.min_m_kg\n",
    "\n",
    "    def get_filling_level_percent(self):\n",
    "        # return the ratio of absolute stored mass and total maximum storable mass in Percent\n",
    "        return 100 * self.get_stored_mass() / self.max_m_kg\n",
    "\n",
    "    def get_free_filling_level_percent(self):\n",
    "        # return the ratio of available stored mass (i.e. excl. min_m_stored_kg) and difference between max and min in Percent\n",
    "        return 100 * self.get_free_stored_mass() / (self.max_m_kg - self.min_m_kg)\n",
    "\n",
    "    # Define which values in the net shall be updated\n",
    "    def write_to_net(self, net):\n",
    "        # write mdot_kg_per_s, m_stored_kg to the table in the net\n",
    "        net.mass_storage.at[self.sid, \"mdot_kg_per_s\"] = self.mdot_kg_per_s\n",
    "        net.mass_storage.at[self.sid, \"m_stored_kg\"] = self.m_stored_kg\n",
    "        net.mass_storage.at[self.sid, \"filling_level_percent\"] = \\\n",
    "            self.get_free_filling_level_percent()\n",
    "        # Note: a pipeflow will automatically be conducted in the run_timeseries / run_control procedure.\n",
    "        # This will then update the result table (net.res_mass_storage).\n",
    "        # If something was written to net.res_mass_storage in this method here, the pipeflow would overwrite it.\n",
    "\n",
    "    # In case the controller is not yet converged (i.e. in the first iteration,\n",
    "    # maybe also more iterations for more complex controllers), the control step is executed.\n",
    "    # In the example it simply adopts a new value according to the previously calculated target\n",
    "    # and writes back to the net.\n",
    "    def control_step(self, net):\n",
    "        # Call write_to_net and set the applied variable True\n",
    "        self.write_to_net(net)\n",
    "        self.applied = True\n",
    "\n",
    "    # convergence check\n",
    "    def is_converged(self, net):\n",
    "        # check if controller already was applied\n",
    "        return self.applied\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We are now ready to create objects of our newly implemented class and use it in a simulation:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "hp.pandapower.control.util.auxiliary - INFO: Creating controller 0 of type <class '__main__.StorageController'> \n"
     ]
    }
   ],
   "source": [
    "import pandas as pd\n",
    "\n",
    "import pandapower.timeseries as ts\n",
    "# importing a grid from the library\n",
    "from pandapipes.networks import gas_meshed_square\n",
    "\n",
    "# loading the network\n",
    "net = gas_meshed_square()\n",
    "pp.pipeflow(net)\n",
    "\n",
    "# creating a simple time series\n",
    "framedata = pd.DataFrame([0.1, .05, -0.1, .005, -0.2, 0], columns=['mdot_storage'])\n",
    "datasource = ts.DFData(framedata)\n",
    "\n",
    "# creating storage unit in the grid, which will be controlled by our controller\n",
    "store_mass = pp.create_mass_storage(net, junction=3,\n",
    "                                    mdot_kg_per_s=0, init_m_stored_kg=2, min_m_stored_kg=0, max_m_stored_kg=500,\n",
    "                                    type=\"classical mass storage\")\n",
    "\n",
    "# creating an Object of our new build storage controller, controlling the storage unit\n",
    "ctrl = StorageController(net=net, sid=store_mass, data_source=datasource, mdot_profile='mdot_storage')"
   ]
  },
  {
   "cell_type": "markdown",
   "source": [
    "If required, we could also pass other arguments to the `create_mass_storage` function as key word arguments, i.e. the floor area of the storage, and use them in the `StorageController` class."
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now we run a small time-series-simulation and track the results using the outputwriter:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "  0%|          | 0/6 [00:00<?, ?it/s]C:\\Users\\e2n236\\AppData\\Local\\Temp\\ipykernel_14224\\856783411.py:50: RuntimeWarning: invalid value encountered in double_scalars\n",
      "  self.mdot_kg_per_s = self.delta_m_kg_real / ((time - self.last_time_step)\n",
      "100%|██████████| 6/6 [00:00<00:00, 73.58it/s]\n"
     ]
    }
   ],
   "source": [
    "from pandapipes.timeseries import run_timeseries\n",
    "# defining an OutputWriter to track certain variables\n",
    "log_variables = [(\"mass_storage\", \"mdot_kg_per_s\"), (\"res_mass_storage\", \"mdot_kg_per_s\"),\n",
    "                 (\"mass_storage\", \"m_stored_kg\")]\n",
    "ow = ts.OutputWriter(net, log_variables=log_variables)\n",
    "\n",
    "# starting time series simulation\n",
    "run_timeseries(net, time_steps=range(0, 6))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "To visualize the results we plot directly with the dataframe:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": "<matplotlib.legend.Legend at 0x219c607cd00>"
     },
     "execution_count": 23,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": "<Figure size 432x288 with 1 Axes>",
      "image/png": "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\n"
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "# plotting the state of charge\n",
    "ow.output['mass_storage.m_stored_kg'].columns = ['mass_storage']\n",
    "ax = ow.output['mass_storage.m_stored_kg'].plot()\n",
    "ax.set_xlabel('Time in 60 min Steps')\n",
    "ax.set_ylabel('stored mass in kg')\n",
    "ax.legend()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
